<!DOCTYPE html>
<html lang="en" dir="ltr">
<!--
Copyright 2008 The Closure Library Authors. All Rights Reserved.

Use of this source code is governed by the Apache License, Version 2.0.
See the COPYING file for details.
-->
<head>
<!--
This test has not yet been updated to run on IE8. See http://b/hotlist?id=36311
-->
<!--meta http-equiv="X-UA-Compatible" content="IE=edge"-->
<meta http-equiv="X-UA-Compatible" content="IE=EmulateIE7">
  <title>Closure Unit Tests - goog.testing.dom</title>
  <script src="../base.js"></script>
  <script>
    goog.require('goog.dom');
    goog.require('goog.dom.TagName');
    goog.require('goog.testing.dom');
    goog.require('goog.testing.jsunit');
    goog.require('goog.userAgent');
  </script>
</head>
<body>
<div id="root"></div>
<script type="text/javascript">
  var root = goog.dom.getElement('root');

  function setUp() {
    root.innerHTML = '';
  }

  function testFindNode() {
    // Test the easiest case.
    root.innerHTML = 'a<br>b';
    assertEquals(goog.testing.dom.findTextNode('a', root), root.firstChild);
    assertEquals(goog.testing.dom.findTextNode('b', root), root.lastChild);
    assertNull(goog.testing.dom.findTextNode('c', root));
  }

  function testFindNodeDuplicate() {
    // Test duplicate.
    root.innerHTML = 'c<br>c';
    assertEquals('Should return first duplicate',
        goog.testing.dom.findTextNode('c', root), root.firstChild);
  }

  function findNodeWithHierarchy() {
    // Test a more complicated hierarchy.
    root.innerHTML = '<div>a<p>b<span>c</span>d</p>e</div>';
    assertEquals(goog.dom.TagName.DIV,
        goog.testing.dom.findTextNode('a', root).parentNode.tagName);
    assertEquals(goog.dom.TagName.P,
        goog.testing.dom.findTextNode('b', root).parentNode.tagName);
    assertEquals(goog.dom.TagName.SPAN,
        goog.testing.dom.findTextNode('c', root).parentNode.tagName);
    assertEquals(goog.dom.TagName.P,
        goog.testing.dom.findTextNode('d', root).parentNode.tagName);
    assertEquals(goog.dom.TagName.DIV,
        goog.testing.dom.findTextNode('e', root).parentNode.tagName);
  }

  function setUpAssertHtmlMatches() {
    var tag1, tag2;
    if (goog.userAgent.IE) {
      tag1 = goog.dom.TagName.DIV;
    } else if (goog.userAgent.WEBKIT) {
      tag1 = goog.dom.TagName.P;
      tag2 = goog.dom.TagName.BR;
    } else if (goog.userAgent.GECKO) {
      tag1 = goog.dom.TagName.SPAN;
      tag2 = goog.dom.TagName.BR;
    }

    var parent = goog.dom.createDom(goog.dom.TagName.DIV);
    root.appendChild(parent);
    parent.style.fontSize = '2em';
    parent.style.display = 'none';
    if (!goog.userAgent.WEBKIT) {
      parent.appendChild(goog.dom.createTextNode('NonWebKitText'));
    }

    if (tag1) {
      var e1 = goog.dom.createDom(tag1);
      parent.appendChild(e1);
      parent = e1;
    }
    if (tag2) {
      parent.appendChild(goog.dom.createDom(tag2));
    }
    parent.appendChild(goog.dom.createTextNode('Text'));
    if (goog.userAgent.WEBKIT) {
      root.firstChild.appendChild(goog.dom.createTextNode('WebKitText'));
    }
  }

  function testAssertHtmlContentsMatch() {
    setUpAssertHtmlMatches();

    goog.testing.dom.assertHtmlContentsMatch(
        '<div style="display: none; font-size: 2em">' +
        '[[!WEBKIT]]NonWebKitText<div class="IE"><p class="WEBKIT">' +
        '<span class="GECKO"><br class="GECKO WEBKIT">Text</span></p></div>' +
        '</div>[[WEBKIT]]WebKitText',
        root);
  }

  function testAssertHtmlMismatchText() {
    setUpAssertHtmlMatches();

    var e = assertThrows('Should fail due to mismatched text', function() {
      goog.testing.dom.assertHtmlContentsMatch(
          '<div style="display: none; font-size: 2em">' +
          '[[IE GECKO]]NonWebKitText<div class="IE"><p class="WEBKIT">' +
          '<span class="GECKO"><br class="GECKO WEBKIT">Bad</span></p></div>' +
          '</div>[[WEBKIT]]Extra',
          root);
    });
    assertContains('Text should match', e.message);
  }

  function testAssertHtmlMismatchTag() {
    setUpAssertHtmlMatches();

    var e = assertThrows('Should fail due to mismatched tag', function() {
      goog.testing.dom.assertHtmlContentsMatch(
          '<span style="display: none; font-size: 2em">' +
          '[[IE GECKO]]NonWebKitText<div class="IE"><p class="WEBKIT">' +
          '<span class="GECKO"><br class="GECKO WEBKIT">Text</span></p></div>' +
          '</span>[[WEBKIT]]Extra',
          root);
    });
    assertContains('Tag names should match', e.message);
  }

  function testAssertHtmlMismatchStyle() {
    setUpAssertHtmlMatches();

    var e = assertThrows('Should fail due to mismatched style', function() {
      goog.testing.dom.assertHtmlContentsMatch(
          '<div style="display: none; font-size: 3em">' +
          '[[IE GECKO]]NonWebKitText<div class="IE"><p class="WEBKIT">' +
          '<span class="GECKO"><br class="GECKO WEBKIT">Text</span></p></div>' +
          '</div>[[WEBKIT]]Extra',
          root);
    });
    assertContains('Should have same styles', e.message);
  }

  function testAssertHtmlMismatchOptionalText() {
    setUpAssertHtmlMatches();

    var e = assertThrows('Should fail due to mismatched text', function() {
      goog.testing.dom.assertHtmlContentsMatch(
          '<div style="display: none; font-size: 2em">' +
          '[[IE GECKO]]Bad<div class="IE"><p class="WEBKIT">' +
          '<span class="GECKO"><br class="GECKO WEBKIT">Text</span></p></div>' +
          '</div>[[WEBKIT]]Bad',
          root);
    });
    assertContains('Text should match', e.message);
  }

  function testAssertHtmlMismatchExtraActualAfterText() {
    root.innerHTML = '<div>abc</div>def';

    var e = assertThrows('Should fail due to extra actual nodes', function() {
      goog.testing.dom.assertHtmlContentsMatch('<div>abc</div>', root);
    });
    assertContains('Finished expected HTML before', e.message);
  }

  function testAssertHtmlMismatchExtraActualAfterElement() {
    root.innerHTML = '<br>def';

    var e = assertThrows('Should fail due to extra actual nodes', function() {
      goog.testing.dom.assertHtmlContentsMatch('<br>', root);
    });
    assertContains('Finished expected HTML before', e.message);
  }

  function testAssertHtmlMatchesWithSplitTextNodes() {
    root.appendChild(goog.dom.createTextNode('1'));
    root.appendChild(goog.dom.createTextNode('2'));
    root.appendChild(goog.dom.createTextNode('3'));
    goog.testing.dom.assertHtmlContentsMatch('123', root);
  }

  function testAssertHtmlMatchesWithDifferentlyOrderedAttributes() {
    root.innerHTML = '<div foo="a" bar="b" class="className"></div>';

    goog.testing.dom.assertHtmlContentsMatch(
        '<div bar="b" class="className" foo="a"></div>', root, true);
  }

  function testAssertHtmlMismatchWithDifferentNumberOfAttributes() {
    root.innerHTML = '<div foo="a" bar="b"></div>';

    var e = assertThrows(function() {
      goog.testing.dom.assertHtmlContentsMatch(
          '<div foo="a"></div>', root, true);
    });
    assertContains('Unexpected attribute with name bar in element', e.message);
  }

  function testAssertHtmlMismatchWithDifferentAttributeNames() {
    root.innerHTML = '<div foo="a" bar="b"></div>';

    var e = assertThrows(function() {
      goog.testing.dom.assertHtmlContentsMatch(
          '<div foo="a" baz="b"></div>', root, true);
    });
    assertContains('Expected to find attribute with name baz', e.message);
  }

  function testAssertHtmlMismatchWithDifferentClassNames() {
    root.innerHTML = '<div class="className1"></div>';

    var e = assertThrows(function() {
      goog.testing.dom.assertHtmlContentsMatch(
          '<div class="className2"></div>', root, true);
    });
    assertContains(
        'Expected class was: className2, but actual class was: className1',
        e.message);
  }

  function testAssertHtmlMatchesWithClassNameAndUserAgentSpecified() {
    root.innerHTML =
        '<div>' + (goog.userAgent.GECKO ? '<div class="foo"></div>' : '') +
        '</div>';

    goog.testing.dom.assertHtmlContentsMatch(
        '<div><div class="foo GECKO"></div></div>',
        root, true);
  }

  function testAssertHtmlMatchesWithClassesInDifferentOrder() {
    root.innerHTML = '<div class="class1 class2"></div>';

    goog.testing.dom.assertHtmlContentsMatch(
        '<div class="class2 class1"></div>', root, true);
  }

  function testAssertHtmlMismatchWithDifferentAttributeValues() {
    root.innerHTML = '<div foo="b" bar="a"></div>';

    var e = assertThrows(function() {
      goog.testing.dom.assertHtmlContentsMatch(
          '<div foo="a" bar="a"></div>', root, true);
    });
    assertContains('Expected attribute foo has a different value', e.message);
  }

  function testAssertHtmlMatchesWhenStrictAttributesIsFalse() {
    root.innerHTML = '<div foo="a" bar="b"></div>';

    goog.testing.dom.assertHtmlContentsMatch('<div foo="a"></div>', root);
  }

  function testAssertHtmlMatchesForMethodsAttribute() {
    root.innerHTML = '<a methods="get"></a>';

    goog.testing.dom.assertHtmlContentsMatch('<a></a>', root);
    goog.testing.dom.assertHtmlContentsMatch('<a methods="get"></a>', root);
    goog.testing.dom.assertHtmlContentsMatch('<a methods="get"></a>', root,
        true);
  }

  function testAssertHtmlMatchesForMethodsAttribute() {
    root.innerHTML = '<input></input>';

    goog.testing.dom.assertHtmlContentsMatch('<input></input>', root);
    goog.testing.dom.assertHtmlContentsMatch('<input></input>', root, true);
  }

  function testAssertHtmlMatchesForIdAttribute() {
    root.innerHTML = '<div id="foo"></div>';

    goog.testing.dom.assertHtmlContentsMatch('<div></div>', root);
    goog.testing.dom.assertHtmlContentsMatch('<div id="foo"></div>', root);
    goog.testing.dom.assertHtmlContentsMatch('<div id="foo"></div>', root,
        true);
  }

  function testAssertHtmlMatchesWhenIdIsNotSpecified() {
    root.innerHTML = '<div id="someId"></div>';

    goog.testing.dom.assertHtmlContentsMatch('<div></div>', root);
  }

  function testAssertHtmlMismatchWhenIdIsNotSpecified() {
    root.innerHTML = '<div id="someId"></div>';

    var e = assertThrows(function() {
      goog.testing.dom.assertHtmlContentsMatch('<div></div>', root, true);
    });
    assertContains('Unexpected attribute with name id in element', e.message);
  }

  function testAssertHtmlMismatchWhenIdIsSpecified() {
    root.innerHTML = '<div></div>';

    var e = assertThrows(function() {
      goog.testing.dom.assertHtmlContentsMatch('<div id="someId"></div>', root);
    });
    assertContains('Expected to find attribute with name id, in element',
        e.message);

    e = assertThrows(function() {
      goog.testing.dom.assertHtmlContentsMatch('<div id="someId"></div>', root,
          true);
    });
    assertContains('Expected to find attribute with name id, in element',
        e.message);
  }

  function testAssertHtmlMatchesWhenIdIsEmpty() {
    root.innerHTML = '<div></div>';

    goog.testing.dom.assertHtmlContentsMatch('<div></div>', root);
    goog.testing.dom.assertHtmlContentsMatch('<div></div>', root, true);
  }

  function testAssertHtmlMatchesWithDisabledAttribute() {
    var disabledShortest = '<input disabled>';
    var disabledShort = '<input DISABLED="">';
    var disabledLong = '<input disabled="disabled">';
    var enabled = '<input>';

    root.innerHTML = disabledLong;
    goog.testing.dom.assertHtmlContentsMatch(disabledShortest, root, true);
    goog.testing.dom.assertHtmlContentsMatch(disabledShort, root, true);
    goog.testing.dom.assertHtmlContentsMatch(disabledLong, root, true);


    var e = assertThrows('Should fail due to mismatched text', function() {
      goog.testing.dom.assertHtmlContentsMatch(enabled, root, true);
    });
    // Attribute value mismatch in IE.
    // Unexpected attribute error in other browsers.
    assertContains('disabled', e.message);
  }

  function testAssertHtmlMatchesWithCheckedAttribute() {
    var checkedShortest = '<input type="radio" name="x" checked>';
    var checkedShort = '<input type="radio" name="x" CHECKED="">';
    var checkedLong = '<input type="radio" name="x" checked="checked">';
    var unchecked = '<input type="radio" name="x">';

    root.innerHTML = checkedLong;
    goog.testing.dom.assertHtmlContentsMatch(checkedShortest, root, true);
    goog.testing.dom.assertHtmlContentsMatch(checkedShort, root, true);
    goog.testing.dom.assertHtmlContentsMatch(checkedLong, root, true);
    if (!goog.userAgent.IE) {
      // CHECKED attribute is ignored because it's among BAD_IE_ATTRIBUTES_.
      var e = assertThrows('Should fail due to mismatched text', function() {
        goog.testing.dom.assertHtmlContentsMatch(unchecked, root, true);
      });
      assertContains('Unexpected attribute with name checked', e.message);
    }
  }

  function testAssertHtmlMatchesWithWhitespace() {
    root.innerHTML = '';
    root.appendChild(goog.dom.createTextNode('  A  '));
    goog.testing.dom.assertHtmlContentsMatch('  A  ', root);

    root.innerHTML = '';
    root.appendChild(goog.dom.createTextNode('  A  '));
    root.appendChild(goog.dom.createDom('span', null, '  B  '));
    root.appendChild(goog.dom.createTextNode('  C  '));
    goog.testing.dom.assertHtmlContentsMatch(
        '  A  <span>  B  </span>  C  ', root);

    root.innerHTML = '';
    root.appendChild(goog.dom.createTextNode('  A'));
    root.appendChild(goog.dom.createDom('span', null, '  B'));
    root.appendChild(goog.dom.createTextNode('  C'));
    goog.testing.dom.assertHtmlContentsMatch(
        '  A<span>  B</span>  C', root);
  }

  function testAssertHtmlMatchesWithWhitespaceAndNesting() {
    root.innerHTML = '';
    root.appendChild(goog.dom.createDom('div', null,
        goog.dom.createDom('b', null, '  A  '),
        goog.dom.createDom('b', null, '  B  ')));
    root.appendChild(goog.dom.createDom('div', null,
        goog.dom.createDom('b', null, '  C  '),
        goog.dom.createDom('b', null, '  D  ')));

    goog.testing.dom.assertHtmlContentsMatch(
        '<div><b>  A  </b><b>  B  </b></div>' +
        '<div><b>  C  </b><b>  D  </b></div>', root);

    root.innerHTML = '';
    root.appendChild(goog.dom.createDom('b', null,
        goog.dom.createDom('b', null,
            goog.dom.createDom('b', null, '  A  '))));
    root.appendChild(goog.dom.createDom('b', null, '  B  '));

    goog.testing.dom.assertHtmlContentsMatch(
        '<b><b><b>  A  </b></b></b><b>  B  </b>', root);

    root.innerHTML = '';
    root.appendChild(goog.dom.createDom('div', null,
        goog.dom.createDom('b', null,
            goog.dom.createDom('b', null, '  A  '))));
    root.appendChild(goog.dom.createDom('b', null, '  B  '));

    goog.testing.dom.assertHtmlContentsMatch(
        '<div><b><b>  A  </b></b></div><b>  B  </b>', root);

    root.innerHTML = '&nbsp;';
    goog.testing.dom.assertHtmlContentsMatch(
        '&nbsp;', root);
  }

  function testAssertHtmlMatches() {
    // Since assertHtmlMatches is based on assertHtmlContentsMatch, we leave the
    // majority of edge case testing to the above.  Here we just do a sanity
    // check.
    goog.testing.dom.assertHtmlMatches('<div>abc</div>', '<div>abc</div>');
    goog.testing.dom.assertHtmlMatches('<div>abc</div>', '<div>abc</div> ');
    goog.testing.dom.assertHtmlMatches(
        '<div style="font-size: 1px; color: red">abc</div>',
        '<div style="color: red;  font-size: 1px;;">abc</div>');

    var e = assertThrows('Should fail due to mismatched text', function() {
      goog.testing.dom.assertHtmlMatches('<div>abc</div>', '<div>abd</div>');
    });
    assertContains('Text should match', e.message);
  }
</script>
</body>
</html>
